import 'dart:async';
import 'package:agora_rtc_engine/agora_rtc_engine.dart';
import 'package:ayj_flutter_chat_app/common/configs/project_config.dart';
import 'package:ayj_flutter_chat_app/pages/chat/video/video_controller.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../../../../pages/chat/chat_page/chat_controller.dart';
import '../components/log_sink.dart';
import '../config/agora.config.dart' as config;

class AgoraEngineVideo extends StatelessWidget{
  static final AgoraEngineVideo _singleton = AgoraEngineVideo._internal();

  factory AgoraEngineVideo() {
    return _singleton;
  }

  AgoraEngineVideo._internal();

  @override
  Widget build(BuildContext context) {
    AgoraEngineController agoraEngineController = AgoraEngineController.to;
    return AgoraVideoView(
      controller: VideoViewController.remote(
        rtcEngine: agoraEngineController.getRtcEngine(),
        canvas: VideoCanvas(uid: agoraEngineController.remoteUid.first),
        connection: RtcConnection(channelId: agoraEngineController.channelID),
      ),
      onAgoraVideoViewCreated: (viewId) {
        agoraEngineController.engine?.startPreview();
      },
    );
  }

}

class AgoraEngineController extends GetxController {
  static AgoraEngineController get to => Get.find();

  final double buttonsW = JhScreenUtils.screenWidth / 5;
  final Rx<bool> isJoined = false.obs,//加入
      switchRender = true.obs,//
      muteCamera = false.obs,
      muteAllRemoteVideo = false.obs,
      speak = true.obs,//麦克风
      voice = true.obs,//声音
      openCamera = true.obs,//摄像头
      switchCamera = false.obs;//后置
  final RxList<int> remoteUid = <int>[].obs;

  final Rx<MeetingStatusType> voiceMeetingType = MeetingStatusType.waiting.obs;

  String channelID = '1';
  int userId = 1;
  final Rx<bool> isBack = false.obs;
  ControllerType cType = ControllerType.forgetPassword;

  Timer? _timer;
  final Rx<int>  count = 0.obs;
  Widget? agoraVideoView;

  ///life
  @override
  void dispose() {
    LogUtils.e('AgoraEngineController dispose');
    disposeEngine();
    ChatController.to.meetingType.value = ControllerType.chat;
    super.dispose();
  }

  receiveOnTap(String channel,int user){
    print('receiveOnTap');
    joinChannel(channelID,userId);
    voiceMeetingType.value = MeetingStatusType.received;
    _startTimer();
  }

  Widget buildAgoraVideoView(context){
    LogUtils.e('agoraVideoView ');
    if(agoraVideoView == null){
      LogUtils.e('buildAgoraVideoView ');
      agoraVideoView = AgoraVideoView(
        controller: VideoViewController.remote(
          rtcEngine: getRtcEngine(),
          canvas: VideoCanvas(uid: remoteUid.first),
          connection: RtcConnection(channelId: channelID),
        ),
        onAgoraVideoViewCreated: (viewId) {
          engine?.startPreview();
        },
      );
    }
    return agoraVideoView!;
  }


  late RtcEngineEventHandler _rtcEngineEventHandler;
  RtcEngine? engine;

  RtcEngine getRtcEngine(){
    return engine ?? createAgoraRtcEngine();
  }

  Future<void> disposeEngine() async {
    if(engine != null){
      engine?.unregisterEventHandler(_rtcEngineEventHandler);
      await engine?.leaveChannel();
      await engine?.release();
    }
    cancelTimer(); // 取消定时器
  }

  Future<void> initEngine(ControllerType type) async {
    // isBack.value = false;
    LogUtils.e('$type == $cType');
    if(type == cType){
      return;
    }else if(type != ControllerType.meetingVoice && type != ControllerType.meetingVideo){
      disposeEngine();
      return;
    }
    cType = type;
    engine = createAgoraRtcEngine();
    await engine?.initialize(RtcEngineContext(
      appId: config.appId,
    ));
    _rtcEngineEventHandler = RtcEngineEventHandler(
      onError: (ErrorCodeType err, String msg) {
        logSink.log('[onError] err: $err, msg: $msg');
      },
      onJoinChannelSuccess: (RtcConnection connection, int elapsed) {
        logSink.log(
            '[onJoinChannelSuccess] connection: ${connection.toJson()} elapsed: $elapsed');
        isJoined.value = true;
      },
      onUserJoined: (RtcConnection connection, int rUid, int elapsed) {
        logSink.log(
            '[onUserJoined] connection: ${connection.toJson()} remoteUid: $rUid elapsed: $elapsed');
        // remoteUid.value = rUid;
        if(!remoteUid.contains(rUid)){
          remoteUid.add(rUid);
        }
        print('add(rUid) remoteUid ==  ${remoteUid}');
      },
      onUserOffline:
          (RtcConnection connection, int rUid, UserOfflineReasonType reason) {
        logSink.log(
            '[onUserOffline] connection: ${connection.toJson()}  rUid: $rUid reason: $reason');
        remoteUid.removeWhere((element) => element == rUid);
        print('removeWhere(rUid) $rUid ${remoteUid}');

        cancelOnTap();
      },
      onLeaveChannel: (RtcConnection connection, RtcStats stats) {
        logSink.log(
            '[onLeaveChannel] connection: ${connection.toJson()} stats: ${stats.toJson()}');
        isJoined.value = false;
        cancelOnTap();
      },
      onRemoteVideoStateChanged: (RtcConnection connection, int remoteUid,
          RemoteVideoState state, RemoteVideoStateReason reason, int elapsed) {
        logSink.log(
            '[onRemoteVideoStateChanged] connection: ${connection.toJson()} remoteUid: $remoteUid state: $state reason: $reason elapsed: $elapsed');
      },
    );

    engine?.registerEventHandler(_rtcEngineEventHandler);
    if(cType == ControllerType.meetingVoice){
      await engine?.enableAudio();
      await engine?.setClientRole(role: ClientRoleType.clientRoleBroadcaster);
      await engine?.setAudioProfile(
          profile: AudioProfileType.audioProfileDefault,
          scenario: AudioScenarioType.audioScenarioGameStreaming,);

    }else{
      await engine?.enableVideo();
    }

  }

  ///click
  Future<void> joinChannel(String channelId, int uid) async {
    await engine?.joinChannel(
      token: config.token,
      channelId: channelId,
      uid: uid,
      options: ChannelMediaOptions(
        channelProfile:  ChannelProfileType.channelProfileLiveBroadcasting,
        clientRoleType: ClientRoleType.clientRoleBroadcaster,
      ),
    );
  }

  cancelOnTap() async {
    await leaveChannel();
    remoteUid.clear();
    count.value = 0;
    disposeEngine();
    onlyPopTap();
    voiceMeetingType.value = MeetingStatusType.waiting;
    ChatController.to.meetingType.value = ControllerType.chat;
    Get.delete<AgoraEngineController>();
  }

  onlyPopTap(){
    LogUtils.e('back ${isBack.value}');
    if(isBack.value  != true){
      isBack.value = true;
      JhNavUtils.back();
      // engine?.stopPreview();
      ChatController.to.meetingType.value = cType;
      // videoOnTap(false);
      Get.delete<VideoController>();
    }
  }

  Future<void> leaveChannel() async {
    await engine?.leaveChannel();
    openCamera.value = true;
    muteCamera.value = false;
    muteAllRemoteVideo.value = false;
  }

  Future<void> changeCameraOnTap(value) async {
    await engine?.switchCamera();
    switchCamera.value = value;
  }

  cameraOnTap(value) async {
    await engine?.enableLocalVideo(value);
    openCamera.value = value;
  }

  ///取消订阅所有远端用户的音频流
  voiceOnTap(value) async {
    await engine?.muteAllRemoteAudioStreams(value);
    voice.value = value;
  }

  ///取消订阅所有用户的视频流。
  videoOnTap(value) async {
    await engine?.muteAllRemoteVideoStreams(value);
    voice.value = value;
  }

  speakOnTap(value) async {
    await engine?.enableLocalAudio(value);
    speak.value = value;
  }

  /// timer
  void cancelTimer(){
    LogUtils.e('cancelTimer');
    _timer?.cancel();
  }

  void _startTimer() {
    if(_timer == null || !(_timer?.isActive ?? false)){
      count.value = 0;
      _timer = Timer.periodic(Duration(seconds: 1), (Timer timer) {
        count.value++;
        LogUtils.e('${count.value}');
      });
    }
  }

}
